Tinker-让android热更新更靠谱

Tinker是微信前段时间开源的Android热补丁方案,它支持动态下发代码、So库以及资源,让应用能够在不需要重新安装的情况下实现更新。今天我们就来介绍下Tinker,希望大家能用到自己的项目中,我自己的项目已经使用了,而且在线上已经稳定运行了大半年了,是个人目前用下来最好的android hot fix方案,在这里感谢微信团队🙏🙏🙏,Tinker的github地址为https://github.com/Tencent/tinker

1 常见android热更新方案

目前常用的方案有Native Hook方案,通过在native代码进行方法hook,这种方式最大的问题在于部分手机需要root后才能hook进程,而且功能太弱,是比较早期的热更新方案,现在应该基本没什么人用了;Classloader方案是用的比较多的一种,其实思路和Multidex是一个思路,就是在加载dex的时候优先加载patch.dex用新类覆盖有bug的类;今天我们要介绍的是通过instance Run替换dex的方案,这种方案最大的好处就是兼容性比较好,而且可以实现类的替换也可以实现资源文件的替换。

原理 方案
native Hook方案 AndFix
ClassLoader替换类方案 Nuwa、HotFix
Instance Run冷插拔dex替换 Tinker
测试模块 nativehook Classloader方案 InstanceRun方案
类替换 no yes yes
资源替换 no no yes
是否需要重启 no yes yes
兼容稳定性 不稳定 最好 稳定

这里再贴下tinker官网对各个主流hot fix方案的对比,对比下来还是很不错的:

Tinker QZone AndFix Robust
类替换 yes yes no no
So替换 yes no no no
资源替换 yes yes no no
全平台支持 yes yes yes yes
即时生效 no no yes yes
性能损耗 较小 较大 较小 较小
补丁包大小 较小 较大 一般 一般
开发透明 yes yes no no
复杂度 较低 较低 复杂 复杂
gradle支持 yes no no no
Rom体积 较大 较小 较小 较小
成功率 较高 较高 一般 最高

2 Tinker方案设计思想

Tinker的方案对比其他方案为什么会有那么多好处?主要是因为Tinker采用的是全量Dex替换策略,这样不但可以避免ART地址错乱问题,也可以解决在Dalvik上需要插桩的麻烦,tinkerPatch直接使用基准apk包与新编译出来的apk包做差异,得到最终的补丁包。在运行的时候,将差异的patch.dex重新跟原始安装包里的Dex组合为新Dex。在启动的时候ClassLoader会加载最新的Dex,这样就做到了热修复,除了可以用来修复bug,甚至一些new feature也可以使用tinker来发布。为了保证patch.dex比较小,微信团队自研了DexDiff算法可以做到非常小的差量包。为了保证dex合并的性能,Tinker会在后台启动一个patch Process来进行dex合并,让用户感知不到,在下次启动的时候,新的dex就会生效。

这里盗用一张Tinker的原理图,让大家秒懂大概的原理。

https://raw.githubusercontent.com/WeMobileDev/article/master/assets/tinker/wechat.png

3 实施

3.1 引入Tinker

在项目的build.gradle中添加tinker-patch-gradle-plugin依赖

buildscript {
    dependencies {
        classpath ('com.tencent.tinker:tinker-patch-gradle-plugin:1.9.1')
    }
}
dependencies {
    //可选,用于生成application类 
    provided('com.tencent.tinker:tinker-android-anno:1.9.1')
    //tinker的核心库
    compile('com.tencent.tinker:tinker-android-lib:1.9.1') 
}
//apply tinker插件
apply plugin: 'com.tencent.tinker.patch'

3.2 初始化

首先需要定义一个继承自DefaultApplicationLike的类,这个类是com.tencent.tinker.loader.app包下的一个类,可以把这个类当作Application去用,目前我的项目里就是把这个类当作Application去用了。在类的头部需要加上@DefaultLifeCycle注解,用来在编译的时候动态生成SimpleTinkerInApplication这个类,然后需要在app的androidMainfest.xml里设置Application name为注解里设置的动态生成的这个Application类。

@DefaultLifeCycle(application = ".SimpleTinkerInApplication",
        flags = ShareConstants.TINKER_ENABLE_ALL,
        loadVerifyFlag = false)
public class SimpleTinkerInApplicationLike extends ApplicationLike {
    public SimpleTinkerInApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }

    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        TinkerInstaller.install(this);
    }
}

3.3 调用API

在patch下发后,我们可以在一些隐蔽的地方调用Tinker加载patch的方法,我的项目里是放在用户进入app后进行版本检测的时候如果发现服务端有新patch需要更新,则异步下载,在完成下载后调用该方法loadpatch,load完成后Tinker是需要下次启动才会生效的,用户下次再进入app的时候看到的就是打过patch的版本了。

TinkerInstaller.onReceiveUpgradePatch(getApplicationContext(),
                Environment.getExternalStorageDirectory().getAbsolutePath() + "/patch_signed.apk");

3.4 生成patch包

tinker提供了patch生成的工具,源码见:tinker-patch-cli,打成一个jar就可以使用,并且提供了命令行相关的参数以及文件。

执行下面的jar包就可以在output目录生成patch差量包。

java -jar tinker-patch-cli.jar -old old.apk -new new.apk -config tinker_config.xml -out output

在build/output目录下会生成下面这些文件,其中patch_signed_7zip.apk是我们最后发布补丁要用的apk差量文件:

文件名 描述
patch_unsigned.apk 没有签名的补丁包
patch_signed.apk 签名后的补丁包
patch_signed_7zip.apk 签名后并使用7zip压缩的补丁包,也是我们通常使用的补丁包。但正式发布的时候,最好不要以.apk结尾,防止被运营商挟持。
log.txt 在编译补丁包过程的控制台日志
dex_log.txt 在编译补丁包过程关于dex的日志
so_log.txt 在编译补丁包过程关于lib的日志
tinker_result 最终在补丁包的内容,包括diff的dex、lib以及assets下面的meta文件
resources_out.zip 最终在手机上合成的全量资源apk,你可以在这里查看是否有文件遗漏
tempPatchedDexes 在Dalvik与Art平台,最终在手机上合成的完整Dex,我们可以在这里查看dex合成的产物。

3.5 patch分发管理

patch分发涉及到主版本和补丁版本的依赖关系,所以需要在服务端进行管理哪些手机需要推送补丁包,出问题后如何回滚等等问题,补丁包管理可以和自己产品的版本管理结合起来自研,也可以使用Tinker团队开发的patch发布管理平台。

Tinker团队还同步开发了一个patch发布管理的三方平台,对于规模较小的团队或者个人开发者完全可以使用TinkerPatch这个免费的平台进行补丁包的发放和管理,日请求量<1w,赠送的每月cdn流量包是10g,所以一般规模的小app足够使用了。下面是TinkerPatch的地址 http://www.tinkerpatch.com

4 实施注意点

  1. tinker需要在AndroidManifest.xml中指定TINKER_ID;
<application>
  <meta-data
            android:name="TINKER_ID"
            android:value="tinker_id_1234567" />
    //...
</application>
  1. 添加SDCard权限,因为patch会下载到sdcard所以需要sdcard权限,如果你是6.0以上的系统,需要添加上授权代码,或者手动在设置页面打开SDCard读写权限;
  2. 对于项目中自定义了Application的APP需要注意下,建议将原先Application里app初始化的内容都搬迁到新建的ApplicationLike类中,替换掉原先的Application;
  3. 建议直接将tinker github上sample目录中的tinker相关的java代码和gradle和自己的工程内容合并,这样可以很快集成Tinker,避免出现一些问题出现,起码我的项目一开始还不熟的时候是这样实施的。。。后期熟悉Tinker后可以随意灵活使用;
  4. 使用Proguard做混淆的同学还需要注意设置下;
  5. Tinker的常见问题可以参考官网的QA,在使用的过程中遇到的问题基本都涵盖了 官网QA

5 总结

Tinker在我的项目实施的过程中暂时没有遇到不能解决的问题,目前Tinker在项目中主要还是用来修复bug使用,还没有作为new feature发布使用,不过这样的热更效率和稳定性,作为new feature使用也是可以的,自从使用了Tinker后目前还没有遇到以前使用Andfix遇到的一些crash的问题,上了Tinker以后最大的好处就是每次发版后再也不用担心出问题后需要赶急忙慌的修bug去市场上架,再期待着用户点击更新了。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容